#include "uart.h"
#include <stdio.h>

static volatile uint8_t uart_buf;
static volatile int non_empty = 0;

#define UCSR1A_CFG        (_BV(U2X1))
#define UCSR1B_CFG        ( _BV(TXEN1))
#define UCSR1C_CFG        (_BV(UCSZ11) | _BV(UCSZ10))

/** UBn = f_OSC * (1 + value(U2Xn)) / (16 * BAUD) - 1  in floating point arithmetic. */
#define UBRR1_CFG    \
(((    \
    F_CPU * (((UCSR1A_CFG & _BV(U2X1)) >> U2X1) + 1)    \
    / 8 / BAUD    \
) - 1) / 2)

#define UBRR1H_CFG        (UBRR1_CFG >> 8)
#define UBRR1L_CFG        (UBRR1_CFG & 0xFF)

#define TXIntEnable()    UCSR1B |= _BV(UDRIE1)
#define TXIntDisable()    UCSR1B &= ~(_BV(UDRIE1))
#define Is_TXIntDisabled()    (!(UCSR1B & _BV(UDRIE1)))

void _uart_putchar(char c){
	uint8_t sreg = SREG;
	cli();
	
	uart_buf = c;
	TXIntEnable();
	non_empty = 1;
	
	SREG = sreg;
	while(non_empty);
}

static int uart_putchar(char c, FILE *stream){
	(void) stream;
	if(c == '\n')
		_uart_putchar('\r');
	_uart_putchar(c);
	return 0;
}

static FILE uart_stdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

void uart_init(void){
    UCSR1A = UCSR1A_CFG;
    UCSR1B = UCSR1B_CFG;
    UCSR1C = UCSR1C_CFG;

    UBRR1H = UBRR1H_CFG;
    UBRR1L = UBRR1L_CFG;

    non_empty = 0;

	stdout = &uart_stdout;
}


ISR(USART1_UDRE_vect){
	UDR1 = uart_buf;
	non_empty = 0;
	TXIntDisable();
}


